package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.StringUtils;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    /**
     * 查询资源列表
     * @param param
     * @return
     */
    @Override
    public List<Resource> getList(Map<String, String> param) {
        if (param == null) {
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }
        //获取参数
        String resourceType = param.get("resourceType");
        String parentResourceNo = param.get("parentResourceNo");

//        //如果查询父级资源下的子级资源
//        if (parentResourceNo != null) {
//            //删减父级编号末尾数字
//            parentResourceNo = NoProcessing.processString(parentResourceNo);
//        }

        ResourceDto resourceDto = ResourceDto.builder()
                .resourceType(resourceType)
                .parentResourceNo(parentResourceNo)
                .build();

        //查询数据库资源列表数据
        List<Resource> resources = resourceMapper.selectResources(resourceDto);

        return resources;
    }

    /**
     * 查询资源树形
     * @param resourceDto
     * @return
     */
    @Override
    public TreeVo getResourceAll(ResourceDto resourceDto) {
        ResourceDto dto = ResourceDto.builder()
                .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID)) //截取父级资源编号
                .dataState(SuperConstant.DATA_STATE_0) //正常状态
                .resourceType(SuperConstant.MENU) //类型是菜单m
                .build();

        //查询父级下的所有子级资源
        List<Resource> resources = resourceMapper.selectResources(dto);

        //创建items对象
        List<TreeItemVo> items = new ArrayList<>();

        //创建根节点资源对象
        Resource resource = Resource.builder()
                .resourceNo(SuperConstant.ROOT_PARENT_ID) //父级资源编号
                .resourceName("智慧养老院")
                .build();
        //使用递归函数构建树形结构
        recursionTreeItem(items,resources,resource);

        return TreeVo.builder().items(items).build();
    }


    //使用递归函数构建树形结构
    private void recursionTreeItem(List<TreeItemVo> items, List<Resource> resources, Resource resource) {

        //封装根节点的TreeItemVo对象的属性
        TreeItemVo treeItemVo = TreeItemVo.builder()
                .id(resource.getResourceNo())
                .label(resource.getResourceName())
                .build();

        //获取资源列表中根节点的子级资源
        List<Resource> resourceList = resources.stream().filter(resource1 ->
                resource1.getParentResourceNo().equals(resource.getResourceNo())).collect(Collectors.toList());

        //判断子级资源是否为空
        if (!EmptyUtil.isNullOrEmpty(resourceList)) {
            //创建根节点的childrenList对象
            List<TreeItemVo> childrenList = new ArrayList<>();

            //不为空就遍历子级资源查找其下的子子级资源
            resourceList.forEach(resource1 -> {
                //调用递归函数
                recursionTreeItem(childrenList,resources,resource1);
            });

            //封装TreeItemVo对象的属性
            treeItemVo.setChildren(childrenList);
        }

        //给items对象赋值
        items.add(treeItemVo);

    }

    /**
     * 资源添加
     * @param resourceDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addResource(ResourceDto resourceDto) {
        if (resourceDto == null || resourceDto.getParentResourceNo() == null || resourceDto.getResourceType() ==null) {
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        //判断父资源编号是否达到3级
        if (NoProcessing.processString(resourceDto.getParentResourceNo()).length() >12) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }

        //查询父级资源状态,如果父级是禁用，子级也是禁用
        //1、根据编号查询父级资源
        Resource resource0 = resourceMapper.selectByResourceNo(resource.getParentResourceNo());
        //2、设置子级资源状态
        resource.setDataState(resource0.getDataState());

        //设置资源编号
        String resourceNo = creatResourcrNo(resource.getParentResourceNo());
        resource.setResourceNo(resourceNo);

        //新增资源
        resourceMapper.insertResource(resource);

    }

    //生成资源编号
    private String creatResourcrNo(String parentResourceNo) {

        ResourceDto resourceDto = ResourceDto.builder()
                .parentResourceNo(parentResourceNo)
                .build();
        //查询父级的所有子级资源
        List<Resource> resources = resourceMapper.selectResources(resourceDto);

        //判断父级资源有没有子级资源
        if (resources.size() == 0) {
            //如果没有就直接生成
            String resourceNo = NoProcessing.createNo(parentResourceNo, false);
            return resourceNo;
        }else {
            //如果有先查询子级的最大资源编号
            Long maxNo = resources.stream().map(resource -> Long.valueOf(resource.getResourceNo())).max((o1, o2) -> (int) (o1 - o2)).get();
            String resourceNo = NoProcessing.createNo(maxNo.toString(), true);
            return resourceNo;
        }

    }

    /**
     * 资源修改
     * @param resourceDto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateResource(ResourceDto resourceDto) {
        if (resourceDto == null || resourceDto.getId() == null) {
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }

        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);

        //若当前资源的父级编号发生变化，则其下所有子级资源一同变化
        //1、查询当前资源信息
        Resource resource0 = resourceMapper.selectById(resource.getId());
        //2、判断当前资源的父级编号是否发生变化
        if (resource0.getParentResourceNo().equals(resource.getParentResourceNo())) {
            //如果没有发生变化，则直接修改
            resourceMapper.updateResource(resource);
        }else {
            //查询当前资源是否存在所有子级资源
            String resourceNo = NoProcessing.processString(resource0.getResourceNo());
            ResourceDto dto = ResourceDto.builder().parentResourceNo(resourceNo).build();
            List<Resource> resources = resourceMapper.selectResources(dto);
            if (resources.size() == 0) {
                //如果当前没有子级资源,判断父级资源编号是否达到3级
                if (NoProcessing.processString(resourceDto.getParentResourceNo()).length() >12) {
                    throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
                }
                //修改资源
                resourceMapper.updateResource(resource);

            }else {
                //判断最大的编号是几级
                Long maxNo = resources.stream().map(r -> Long.valueOf(r.getResourceNo())).max((o1, o2) -> (int) (o1 - o2)).get();
                int max = NoProcessing.processString(maxNo.toString()).length() / 3;
                //当前资源编号是几级
                int min = NoProcessing.processString(resource0.getResourceNo()).length() / 3;
                int num = max - min +1; //当前资源及其下所有资源占用的等级
                //判断要更改的父级资源编号等级是否小于等于5-num
                if (NoProcessing.processString(resource.getParentResourceNo()).length() / 3 + num <= 5) {
                    // 递归更新当前资源及其所有子级资源的父级编号
                    //updateParentResourceNo(resource, resource.getParentResourceNo(),creatResourcrNo(resource.getParentResourceNo()));

                    //更新资源信息
                    resourceMapper.updateResource(resource);
                }else {
                    throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
                }
            }
        }
    }

    /**
     * 递归更新资源及其所有子级资源的父级编号。
     *
     * @param resource 要更新的资源
     * @param parentResourceNo 新的父级资源编号
     * @param resourceNo 新的资源编号
     */
    private void updateParentResourceNo(Resource resource, String parentResourceNo,String resourceNo) {
        // 查询当前资源的所有子级资源
        ResourceDto dto = ResourceDto.builder().parentResourceNo(resource.getResourceNo()).build();
        List<Resource> childResources = resourceMapper.selectResources(dto);

        // 更新当前资源的父级编号
        resource.setParentResourceNo(parentResourceNo);
        resource.setResourceNo(resourceNo);
        resourceMapper.updateResource(resource);


        // 递归地更新每个子级资源
        for (Resource childResource : childResources) {
            updateParentResourceNo(childResource, resourceNo,creatResourcrNo(resourceNo));
        }
    }


    /**
     * 修改资源启用禁用状态
     * @param resourceDto
     */
    @Override
    public void updateStatus(ResourceDto resourceDto) {
        if (resourceDto == null || resourceDto.getDataState() == null) {
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }

        //查询父级资源信息
        Resource parentResource = resourceMapper.selectByResourceNo(resourceDto.getParentResourceNo());
        //查询当前资源的所有子级
        ResourceDto dto = ResourceDto.builder().parentResourceNo(NoProcessing.processString(resourceDto.getResourceNo())).build();
        List<Resource> resources = resourceMapper.selectResources(dto);

        //如果要变为启用，查询父级资源状态是否为禁用
        if (resourceDto.getDataState().equals(SuperConstant.DATA_STATE_0)) { //0表示要启用
            if (parentResource.getDataState().equals(SuperConstant.DATA_STATE_0)) {
                //更新当前资源状态为启用
                Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
                resourceMapper.updateStatusByNo(resource);

                //判断是否存在子级资源
                if (resources != null && resources.size() != 0) {
                    List<String> resourceNos = resources.stream().map(Resource::getResourceNo).collect(Collectors.toList());
                    //批量更新资源状态
                    resourceMapper.updateStatusByNos(resourceNos,SuperConstant.DATA_STATE_0);
                }
            }else {
                //父级资源状态是禁用不能启用
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }
        else { //表示要禁用当前资源
            //更新当前资源状态为禁用
            Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
            resourceMapper.updateStatusByNo(resource);

            //判断当前资源是否存在子级，如果有则一同更改为禁用
            if (resources != null && resources.size() != 0) {
                List<String> resourceNos = resources.stream().map(Resource::getResourceNo).collect(Collectors.toList());
                //批量更新资源状态
                resourceMapper.updateStatusByNos(resourceNos,SuperConstant.DATA_STATE_1);
            }

        }
    }

    /**
     * 删除菜单资源
     * @param menuId
     */
    @Override
    public void deleteResourceById(String menuId) {
        if (menuId == null) {
            throw new BaseException(BasicEnum.PARAM_ERROR);
        }
        //获取到当前资源信息
        Resource resource = resourceMapper.selectByResourceNo(menuId);

        //查询资源是否是启用状态，启用不能删除
        if (resource.getDataState().equals(SuperConstant.DATA_STATE_0)) {
            throw new BaseException(BasicEnum.MENU_ENABLE);
        }else {
            //如果存在子级资源，则不能删除
            ResourceDto resourceDto = ResourceDto.builder().parentResourceNo(menuId).build();
            List<Resource> resourceList = resourceMapper.selectResources(resourceDto);
            if (resourceList != null && resourceList.size() != 0 ) {
                throw new BaseException(BasicEnum.CHRAND_MENUM_EXISTENCE);
            }

            //不存在子级资源直接删除
            resourceMapper.deleteByResourceNo(menuId);
        }


    }


    /**
     * 获取当前用户动态菜单资源
     * @return
     */
    @Override
    public List<MenuVo> getMenusResource() {

        //根据当前登录用户查询资源信息
        Long userId = UserThreadLocal.getUserId();
        List<MenuVo> menuVoList = resourceMapper.selectByUserId(userId);

        if (StringUtils.isEmpty(menuVoList)) {
            //如果菜单资源为空
            throw new BaseException(BasicEnum.USER_ROLE_AND_MENU_EMPTY);
        }

        //根据父级资源编号分组
        Map<String, List<MenuVo>> parentMenu = menuVoList.stream().collect(Collectors.groupingBy(MenuVo::getParentResourceNo));

        //遍历资源菜单数据
        menuVoList.forEach(menuVo -> {
            //给redirect属性赋值
            menuVo.setRedirect("/"+menuVo.getName());
            //给meta属性赋值
            menuVo.setMeta(MenuMetaVo.builder().title(menuVo.getName()).build());

            //获取当前资源编号的子级资源
            List<MenuVo> menuVos = parentMenu.get(menuVo.getResourceNo());

            //判断是否有子级资源
            if (!StringUtils.isEmpty(menuVos)) {
                //遍历子级资源
                menuVos.forEach(menuVo1 -> {
                    //给redirect属性赋值
                    menuVo1.setRedirect("/"+menuVo1.getName());
                    //给meta属性赋值
                    menuVo1.setMeta(MenuMetaVo.builder().title(menuVo1.getName()).build());

                });

                //给children属性赋值
                menuVo.setChildren(menuVos);
            }
        });

        return parentMenu.get(SuperConstant.ROOT_PARENT_ID);
    }
}
